package com.zxy.supplier_system.server.service

import com.zxy.supplier_system.server.controller.GoodsController
import com.zxy.supplier_system.server.controller.GoodsController.GoodsDetail.SubGoodsResponse
import com.zxy.supplier_system.server.controller.ProcurementSupplierController
import com.zxy.supplier_system.server.entity.ProcurementSupplier
import com.zxy.supplier_system.server.repository.GoodsRepository
import com.zxy.supplier_system.server.repository.ProcurementSupplierRepository
import com.zxy.supplier_system.server.repository.QueryGoodsUnitResponse
import com.zxy.supplier_system.server.repository.SystemServiceRepository
import com.zxy.supplier_system.server.repository.toQueryGoodsUnitResponse
import com.zxy.supplier_system.server.utils.IntIdAndName
import com.zxy.supplier_system.server.utils.orElse404
import com.zxy.supplier_system.server.utils.toIntIdAndName
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.math.BigDecimal

@Service
class ProcurementSupplierService(
    private val procurementSupplierRepository: ProcurementSupplierRepository,
    private val systemServiceService: SystemServiceService,
    private val employeeOperateRecordService: EmployeeOperateRecordService,
    private val goodsRepository: GoodsRepository,
) {


    @Transactional(readOnly = true)
    fun queryProcurementSuppliers(
        pageable: Pageable,
        queryProcurementSuppliersRequest: ProcurementSupplierController.QueryProcurementSuppliersRequest
    ): Page<ProcurementSupplierController.QueryProcurementSuppliersResponse> {
        return this.procurementSupplierRepository.findAll(
            ProcurementSupplierRepository.Specifications.fromQueryProcurementSupplier(queryProcurementSuppliersRequest)
                .and(
                    SystemServiceRepository.Specifications.systemServiceEquals(
                        { root -> root },
                        systemServiceService.getCurrentSystemService()
                    )
                ),
            pageable
        ).map { procurementSupplier ->
            ProcurementSupplierController.QueryProcurementSuppliersResponse(
                procurementSupplier.name,
                procurementSupplier.id,
                procurementSupplier.procurements.count {
                    it.submittedDateTime != null
                },
                procurementSupplier.procurements.mapNotNull { it.submittedDateTime }.maxOrNull()
            )
        }
    }

    @Transactional
    fun updateProcurementSupplier(
        id: Int,
        updateProcurementSupplierRequest: ProcurementSupplierController.UpdateProcurementSupplierRequest
    ) {
        val procurementSupplier = this.procurementSupplierRepository.findByIdOrNull(id).orElse404()
        procurementSupplier.name = updateProcurementSupplierRequest.name
        this.procurementSupplierRepository.save(procurementSupplier)
        this.employeeOperateRecordService.updateProcurementSupplier(procurementSupplier)
    }

    @Transactional
    fun createProcurementSupplier(updateProcurementSupplierRequest: ProcurementSupplierController.UpdateProcurementSupplierRequest): Int {
        val procurementSupplier = this.procurementSupplierRepository.save(ProcurementSupplier().apply {
            name = updateProcurementSupplierRequest.name
            systemService = systemServiceService.getCurrentSystemService()
        })
        this.employeeOperateRecordService.createProcurementSupplier(procurementSupplier)
        return procurementSupplier.id
    }

    @Transactional
    fun deleteProcurementSupplier(id: Int) {
        this.procurementSupplierRepository.deleteById(id)
    }


    fun getAllProcurementSuppliers(): List<IntIdAndName> {
        return this.procurementSupplierRepository.findAllBySystemService(systemServiceService.getCurrentSystemService())
            .map {
                IntIdAndName(it.id, it.name)
            }
    }

    @Transactional(readOnly = true)
    fun getProcurementSupplierDetail(id: Int): ProcurementSupplierDetail {
        return with(
            this.procurementSupplierRepository.findByIdAndSystemService(
                id,
                systemServiceService.getCurrentSystemService()
            )
                .orElse404()
        ) {
            ProcurementSupplierDetail(this.id, this.name, this.selectableBrands.map { it.toIntIdAndName() })
        }
    }

    fun queryProcurementSupplierSummary(keyword: String?, pageable: Pageable): Page<IntIdAndName> {
        return this.procurementSupplierRepository.findAll(
            ProcurementSupplierRepository.Specifications.nameContains(
                keyword
            ), pageable
        ).map {
            it.toIntIdAndName()
        }
    }

    data class ProcurementSupplierDetail(
        val id: Int,
        val name: String,
        val selectableBrands: List<IntIdAndName>,
    )


    @Transactional(readOnly = true)
    fun findAllGoodsWithHistoryProcurement(id: Int): List<GoodsSummaryWithRememberedPurchasePriceWithSubGoods> {
        return this.goodsRepository.findAllWithRememberedProcurementPurchasePrice(id).map {
            val goods = it.goods
            GoodsSummaryWithRememberedPurchasePriceWithSubGoods(
                goods.id,
                goods.name,
                goods.barcode,
                goods.price,
                it.rememberedPurchasePrice?:goods.costPrice,
                it.rememberedUnitId,
                it.rememberedAmount,
                it.subGoods?.let(
                    SubGoodsResponse::fromSubGoods
                ),
                goods.units.map { it.toQueryGoodsUnitResponse() }
            )
        }
    }

    class GoodsSummaryWithRememberedPurchasePriceWithSubGoods(
        val id: Int,
        val name: String,
        val barcode: String,
        val price: BigDecimal,
        val rememberedPurchasePrice: BigDecimal?,
        val rememberedUnitId: Long?,
        val rememberedAmount: Int?,
        val subGoods: SubGoodsResponse?,
        val units:List<QueryGoodsUnitResponse>,
    )

    @Transactional(readOnly = true)
    fun findAllGoodsWithHistoryProcurementReturn(id: Int): List<GoodsSummaryWithRememberedReturnPriceWithSubGoods> {
        return this.goodsRepository.findAllWithRememberedProcurementReturnPrice(id).map {
            val goods = it.goods
            GoodsSummaryWithRememberedReturnPriceWithSubGoods(
                goods.id,
                goods.name,
                goods.barcode,
                goods.price,
                it.price?:goods.costPrice,
                it.subGoods?.let(SubGoodsResponse::fromSubGoods),
            )
        }

    }

    data class GoodsSummaryWithRememberedReturnPriceWithSubGoods(
        val id: Int,
        val name: String,
        val barcode: String,
        val price: BigDecimal,
        val rememberedPrice: BigDecimal?,
        val subGoods: SubGoodsResponse?,
    )
}
